package com.wangxiaonan.coupon.service.impl;

import com.wangxiaonan.coupon.common.Constant;
import com.wangxiaonan.coupon.common.exception.ResourceNotFoundException;
import com.wangxiaonan.coupon.common.exception.ServiceException;
import com.wangxiaonan.coupon.config.RedisManeger;
import com.wangxiaonan.coupon.domain.CouponInfo;
import com.wangxiaonan.coupon.domain.CouponIssue;
import com.wangxiaonan.coupon.repository.CouponIssueDao;
import com.wangxiaonan.coupon.service.CouponIssueService;
import java.util.Optional;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

@Service
@Transactional
public class CouponIssueServiceImpl implements CouponIssueService {

    private static final Logger logger = LoggerFactory.getLogger(CouponInfoServiceImpl.class);

    @Resource
    private CouponIssueDao couponIssueDao;

    @Override
    public CouponIssue receive(String username, CouponInfo couponInfo) {
        Assert.notNull(username, "username 不能为空");
        Assert.notNull(couponInfo, "couponInfo 不能为空");
        Assert.notNull(couponInfo.getId(), "couponInfo.id 不能为空");
        // TODO 校验用户有效性
        logger.info("[TODO 校验用户有效性] 通过");
        // TODO 校验优惠券有效性
        logger.info("[TODO 校验优惠券有效性] 通过");

        // 从优惠券队列中获取券码
        String queueKey = Constant.COUPON_INFO_QUEUE_PREFIX + couponInfo.getId();
        if (RedisManeger.exists(queueKey) <= 0) {
            throw new ResourceNotFoundException("redis resource not found");
        }
        String couponNum;
        try {
            couponNum = RedisManeger.rPop(queueKey);
        } catch (Exception e) {
            logger.error("coupon resource not found", e);
            throw new ResourceNotFoundException("coupon resource not found");
        }
        if (StringUtils.isBlank(couponNum)) {
            throw new ResourceNotFoundException("coupon resource not found");
        }

        // TODO 这一块的逻辑是放在领取时还是更新状态时？？
        CouponIssue issue = new CouponIssue();
        issue.setCouponInfo(couponInfo.getId());
        issue.setUsername(username);
        issue.setStatus(0);
        issue.setIssueNum(couponNum);
        try {
            issue = couponIssueDao.save(issue);
            // 减库存
            RedisManeger.Incrby(Constant.COUPON_CIRCULATION_PREFIX + couponInfo.getId(), -1);
        } catch (Exception e) {
            // 失败时将券码返回券码队列
            RedisManeger.lPush(queueKey, couponNum);
            throw new ServiceException("storage coupon fail");
        }

        logger.info("[领取优惠券] 通过");
        return issue;
    }

    @Override
    public CouponIssue findById(Integer id) {
        Optional<CouponIssue> option = couponIssueDao.findById(id);
        return option.orElse(null);
    }

    @Override
    public CouponIssue save(CouponIssue entity) {
        Assert.notNull(entity, "entity 不能为空");
        if (entity.getStatus() == null) {
            entity.setStatus(0);
        }
        return couponIssueDao.save(entity);
    }

    @Override
    public void deleteById(Integer id) {
        couponIssueDao.deleteById(id);
    }

    @Override
    public CouponIssue update(CouponIssue entity) {
        Assert.notNull(entity, "entity 不能为空");
        Assert.notNull(entity.getId(), "entity.id 不能为空");
        return couponIssueDao.save(entity);
    }
}
